Маленький туториал для MZ. Может кому-то будет полезно (особенно ввиду RTP-марафона).
Если было - сорян, не нашел.
На данный туториал меня "подбили" вопросы Скрипки и старая мысль, на что же способен мейкер без плагинов в контексте работы с внешними данными.
Будет три части:
I. Проверка наличия сохранений в принципе, получение кол-ва сохранений, удаление сохранений.
II. Частичная загрузка сохранений.
III. Лайфхак.
СпойлерПервую часть для MV можно найти в Общих вопросах, в ответе на вопросы Скрипки:
...вторую часть, вероятно, тоже можно сделать - экспериментируйте.
I. Проверка наличия сохранений в принципе, получение кол-ва сохранений, удаление сохранений.
Относительно стандартные действия, которые могут пригодится в ряде случаев.
СпойлерПроверка наличия сохранений в принципе, код для "Скрипта":
Код:
let isThereSaves = DataManager.isAnySavefileExists(); // вернет: true / false.
$gameSwitches.setValue(1, isThereSaves); // если нужно записать есть/нет в переключатель №1.
СпойлерПолучение кол-ва сохранений, код для "Скрипта":
Код:
if( true === DataManager.isAnySavefileExists() ){
const saveFilesList = DataManager._globalInfo;
const savesFullCount = saveFilesList.length; //полный подсчет, с учетом пропусков (если сохранение в слотах 1 и 3, то выдаст что сохранений 3).
const savesAccurateCount = saveFilesList.filter(save => save === save).length; //точный подсчет, с учетом пропусков (если сохранение в слотах 1 и 3, то выдаст что сохранений 2).
$gameVariables.setValue(2, savesAccurateCount); // если нужно записать точное кол-во сохранений в переменную №2.
}else{
console.log('_isThereSaves: false');
}
СпойлерУдаление сохранений:
Файл global.rmmzsave при этом не удаляется.
Запуск кода ниже - исключительно на вашей ответственности.
СпойлерНа свой страх и риск, я предупреждал! Код для "Скрипта":
Код:
if( true === DataManager.isAnySavefileExists() ){
const fs = require("fs"); const path = require('path');
let base = path.dirname(process.mainModule.filename); let savePath = path.join(base, 'save/');
const saveFilesCount = DataManager._globalInfo.length;
for(let n = 0; n < saveFilesCount; n++){
let currentSaveFilePath = savePath + DataManager.makeSavename(n) + '.rmmzsave'; console.log('_delete_currentSaveFilePath:', currentSaveFilePath);
try{ fs.unlinkSync(currentSaveFilePath);
}catch(error){ console.log('_error on deleting saves:', error); }
} console.log('_delete_save_files_process: OK');
}else{
console.log('_isThereSaves: false');
}
II. Частичная загрузка сохранений.
А вот тут интереснее, собственно ради этого я и создал данный мини-туториал.
Как мы знаем, по-дефолту при сохранении в файл записываются переменные, переключатели, локальные переключатели и много чего еще.
При загрузке, соответственно, это все выгружается и применяется мейкером.
Конечно, для сохранения данных (переключателей, переменных, итд) во внешний файл есть ряд плагинов, но...
Но что, если нужно чтоб мейкер выгрузил из "классического сохранения" данные, но их не применил?
То есть, можно ли использовыать классический файл сохранения как внешний источних данных?
Можно!
Т.к. такую возможность, скорее всего, удобнее использовать часто, то запишем функцию загрузки внутрь переменной мейкера:
СпойлерКод функции частичной загрузки данных, для "Скрипта":
Смысл - вызывать функцию, указывая нужный слот сохранения, и записывать результат в отдельную переменную мейкера.
где: N - номер переменной, куда сохранили фунцию. M - номер переменной, куда запишется результат частичной загрузки данных.
Как жы применить это? Сначала вызовем функцию.
СпойлерВызов частичной загрузки данных, для "Скрипта":
Код:
let halfLoader = $gameVariables.value(N);
let halfLoadResult = halfLoader(I);
где: N - номер переменной, куда сохранили фунцию. I - номер файла сохранения
После этого лучше поставить комнду Ждать, на 5-15 кадров (я ставлю на 15).
И, наконец, применение.
А) Просто вывод на консоль (или что-то делать в "Скрипте").
СпойлерВызов частичной загрузки данных, для "Скрипта":
Код:
try{
let halfLoadedData = $gameVariables.value(M);
console.log( halfLoadedData.switches.value(X) ); // получение значения переключателя X из загруженных данных на консоль.
}catch(error){ console.log('_ERROR, load result is:', error); }
где: M - номер переменной, куда записался результат частичной загрузки данных. X - номер интересующего нас переключателя из сохранения. try{}catch(error){} - нужны для отлова ошибки в случае, если данные не загрузились (если такого быть не может, не пишите их).
Б) Проверка в Условии
СпойлерВызов частичной загрузки данных, для Условия и скрипта в нем:
Код:
try{ 33 === $gameVariables.value(M).variables.value(Y); }catch(error){ false; } // получение значения переменной Y из загруженных данных и сравнения како-то числа с ней
где: M - номер переменной, куда записался результат частичной загрузки данных. Y - номер интересующей нас переменной из сохранения. try{}catch(error){} - нужны для отлова ошибки в случае, если данные не загрузились (если такого быть не может, не пишите их).
Конечно, это нужно в довольно редких случаях.
Но если у вас игра, связанная с "зацикливанием", и вы хотите сохранять только промежуточные результаты - это один из вариантов.
Вот перечень данных, которые можно достать из сохранения:
СпойлерНазвание объекта и что содержит:
Код:
system // содержит то же, что и $gameSystem
screen; // содержит то же, что и $gameScreen
timer; // содержит то же, что и $gameTimer
switches; // содержит то же, что и $gameSwitches
variables; // содержит то же, что и $gameVariables
selfSwitches; // содержит то же, что и $gameSelfSwitches
actors; // содержит то же, что и $gameActors
party; // содержит то же, что и $gameParty
map; // содержит то же, что и $gameMap
player;// содержит то же, что и $gamePlayer
III. Лайфхак.
Лайфхак относится к частичной загрузке сохранений.
Например, мы используем такой фокус и не хотим, что бы игрок с этого самого сохранения загружался.
Что делать?
По-дефолту, в мейкере 20 слотов сохранений.
Но сохранять вручную, скриптом, можно в любой слот, даже 20+...То есть сохранить в 21-й слот!
СпойлерКод для ручнуго сохранения в нужный слот, для "Скрипта":
Про удаление сохранений:
- Для инвалидации `_globalInfo` можно использовать метод `DataManager.removeInvalidGlobalInfo(); и следом`DataManager.saveGlobalInfo` - для записи в файл "очищенного" файлаа
Про частичную загрузку
Опять наверное правильных подход все же зависит для чего использовать доп.инфу)
Но данных опять же можно просто "прокинуть" в global сохранение. И это звучит чуть логичнее, с той стороны что на базе Global'a у нас обрисовывается окно загрузки и информация(по сути это аналог headers из мукеров VX XP и прочих).
ЗЫ максимальное количество сохранений в редакторе вообще контролируется вот функцией)
Twitch<- Тут иногда делаю вид, что умею играть или работать, в прямом эфире GitLab<- Тут иногда делаю вид, что умею программировать Github <- Еще какая-то дичь, тут иногда появляется, но с мукером не связана Notion<- Тут иногда делаю вид что умею планировать
А как сделать первый слот зарезервированным для автосейва, чтобы игрок не мог в него сохраняться? Ну чтоб он был серенький такой - пубум. Но загружаться мог?
Дело в том, что у меня уже есть один плагин на сохранения, я боюсь, что будут конфликты. Я хочу в этом конкретно плагине исправить, чтобы первый слот был недоступен. Автосейвы я и вручную делал, они работали прекрасно, а вот какие строчки отвечают за сохранение из меню?
Дело в том, что у меня уже есть один плагин на сохранения, я боюсь, что будут конфликты. Я хочу в этом конкретно плагине исправить, чтобы первый слот был недоступен. Автосейвы я и вручную делал, они работали прекрасно, а вот какие строчки отвечают за сохранение из меню?
По поводу совместимости ты прав.
Для того, чтоб это сделать, я чуть модифицировал "дефолтный код" MV, если правильно помню, то за доступность и цвет слота сохранения отвечает вот эти фрагменты кода:
Спойлеркод:
Код из плагина, с куском моей логики - вырывай её, если не нужна.
Для большего понимания посмотри .js-файлы MV.
Смысл в том, что на экране сохранения:
1) При нажатии на слот движок (Сцена сохранения) должен проверять, доступен ли слот для сохранения.
2) Если слот недоступен, движок (Окно сцены сохранения) отрисовывает его другим - серым - цветом. MV этого не делает, я основывался на подходе MZ.
Код:
//----MODIFY CORE-LIB //--РАСШИРЕНИЕ СТАНДАРТНОГО ФУНКЦИОНАЛА
//--save process //--ДОСТУПНОСТЬ СЛОТА ДЛЯ СОХРАНЕНИЯ
Scene_Save.prototype.onSavefileOk = function() {
Scene_File.prototype.onSavefileOk.call(this);
let savefileId = this.savefileId();
if( true === isSavefileEnabled(savefileId) ){
$gameSystem.onBeforeSave();
if (DataManager.saveGame(this.savefileId())) {
this.onSaveSuccess();
let saveSlotsStatusesList = $gameVariables.value(saveSlotsStatusesListVarId) || [];
saveSlotsStatusesList.push( {slotId: savefileId, slotEnabled: true} );
$gameVariables.setValue(saveSlotsStatusesListVarId, saveSlotsStatusesList);
//saveSlotsStatusesList.push( {slotId: savefileId, slotEnabled: true} );
} else {
this.onSaveFailure();
}
} else {
this.onSaveFailure();
}
};
//--save GUI //--ЦВЕТ СЛОТА ИСХОДЯ ИЗ ДОСТУПНОСТИ
Window_SavefileList.prototype.drawItem = function(index) {
var id = index + 1;
var valid = DataManager.isThisGameFile(id);
valid = isSavefileEnabled(id);
var info = DataManager.loadSavefileInfo(id);
var rect = this.itemRectForText(index);
this.resetTextColor();
if (this._mode === 'load') {
this.changePaintOpacity(valid);
}
this.drawFileId(id, rect.x, rect.y);
if (info) {
this.changePaintOpacity(valid);
this.drawContents(info, rect, valid);
this.changePaintOpacity(true);
}
};
upd:
Наверное, самый быстрый вариант для твоего плагина - контролировать доступность записи по savefileId в Scene_Save.prototype.onSavefileOk.
Последний раз редактировалось Darchan Kaen; 28.07.2022 в 10:40.
А как сделать первый слот зарезервированным для автосейва, чтобы игрок не мог в него сохраняться? Ну чтоб он был серенький такой - пубум. Но загружаться мог?
Что-то вроде такого попробуй. Если будут ошибки и прочее конфликтов с другими плагинами - пиши
Код:
/*:
* @plugindesc ProtectedSaveSlot
* @author F15H
*
* @help save this code as `js/plugins/ProtectedSaveSlot.js' for current plugin work || Для корректной работы плагина сохрани в код как `js/plugins/ProtectedSaveSlot.js`
* @param disabledSaveSlotDisplayName
* @desc The name for the file that will be displayed for disabled save slot || Отображамое имя для слота, в который запрежено сохранение
* @type Text
* @min 0
* @default Autosave
*
* @param disabledSaveSlotIndex
* @desc Slot number where saving is prohibited || Номер слота, в котором запрещено сохранение
* @type Number
* @min 0
* @default 0
*/
(function (){
function toNumber(str, def) {
return isNaN(str) ? def : +(str || def);
}
var PARAMS = PluginManager.parameters('ProtectedSaveSlot');
var disabledSaveSlotIndex = toNumber(PARAMS['disabledSaveSlotIndex'], 0);
var disabledSaveSlotDisplayName = PARAMS['disabledSaveSlotDisplayName'] || "autosave";
Window_SavefileList.prototype.drawItem = function(index) {
var id = index + 1;
var enabled = true;
var valid = DataManager.isThisGameFile(id);
var info = DataManager.loadSavefileInfo(id);
var rect = this.itemRectForText(index);
this.resetTextColor();
if (this._mode === 'load') {
this.changePaintOpacity(valid);
}
var drawTextFunction = this.drawFileId;
if (index === disabledSaveSlotIndex) {
drawTextFunction = this.drawAutosaveFile;
enabled = false;
}
this.changePaintOpacity(enabled && valid);
drawTextFunction.call(this, id, rect.x, rect.y);
if (info) {
this.drawContents(info, rect, valid);
this.changePaintOpacity(true);
}
};
Window_SavefileList.prototype.drawAutosaveFile = function(id, x, y) {
this.drawText(disabledSaveSlotDisplayName, x, y, 180);
};
var Alias_Scene_Save_prototype_onSavefileOk = Scene_Save.prototype.onSavefileOk;
Scene_Save.prototype.onSavefileOk = function() {
var savefileId = this.savefileId();
if (savefileId === (disabledSaveSlotIndex + 1)) {
return this.onSaveFailure();
}
Alias_Scene_Save_prototype_onSavefileOk.call(this);
};
})();
Чтобы нормально подтянулись параметры плагина, назвать файл с кодом `ProtectedSaveSlot.js`
UPD: Были баги - поправил
Последний раз редактировалось Рыб; 28.07.2022 в 21:34.
Twitch<- Тут иногда делаю вид, что умею играть или работать, в прямом эфире GitLab<- Тут иногда делаю вид, что умею программировать Github <- Еще какая-то дичь, тут иногда появляется, но с мукером не связана Notion<- Тут иногда делаю вид что умею планировать
Социальные закладки